import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 参数设置
n = 10   # 训练样本数量
N = 200   # 测试样本数量
m = 5     # 基函数数量

# 生成训练数据
x = np.linspace(-3, 3, n).reshape(-1, 1)
pix = np.pi * x
y = np.sinc(x) + np.cos(pix)/15 + 0.1*x + 0.05*np.random.randn(n, 1)

# 生成测试数据
X = np.linspace(-3, 3, N).reshape(-1, 1)
piX = np.pi * X
yGT = np.sinc(X) + np.cos(piX)/15 + 0.1*X

# 构建设计矩阵
def build_matrix(inputs, m):
    matrix = np.ones((inputs.shape[0], 1))
    for j in range(1, m+1):
        freq = j/2
        matrix = np.hstack((
            matrix, 
            np.sin(freq * inputs),
            np.cos(freq * inputs)
        ))
    return matrix

Q = build_matrix(x, m)
P = build_matrix(X, m)

# 计算最优参数
t = np.linalg.pinv(Q) @ y

# 计算预测值
F_train = Q @ t
F_test = P @ t

# 计算误差
train_error = np.sqrt(np.mean((y - F_train)**2))
test_error = np.sqrt(np.mean((yGT - F_test)**2))

print(f"训练误差: {train_error:.4f}")
print(f"测试误差: {test_error:.4f}")

# 绘图
plt.figure(figsize=(10, 6))
plt.plot(X, yGT, 'k-', lw=2, label='真实模型')
plt.plot(X, F_test, 'b--', lw=2, label='学习模型')
plt.plot(x, y, 'ko', markersize=4, label='样本点')
plt.axis([-2.8, 2.8, -0.5, 1.2])
plt.legend()
plt.xlabel('x')
plt.ylabel('y')
plt.title('最小二乘法拟合结果')
plt.grid(True)
plt.show()